/* WS2812B RGB LED Strip Controller

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/unistd.h>

#include "sdkconfig.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_netif.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_vfs.h"
#include "esp_vfs_fat.h"

#include "nvs_flash.h"
#include "sdmmc_cmd.h"
#include "driver/sdmmc_host.h"

static const char *TAG = "main";
const char *MOUNT_POINT = "/sdcard";

static esp_err_t sdcard_mount(sdmmc_card_t** card)
{
  ESP_LOGI(TAG, "Initializing SD card, Using SDMMC peripheral");

  sdmmc_host_t host = SDMMC_HOST_DEFAULT();

  // This initializes the slot without card detect (CD) and write protect (WP) signals.
  // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
  sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();

  // GPIOs 15, 2, 4, 12, 13 should have external 10k pull-ups.
  // Internal pull-ups are not sufficient. However, enabling internal pull-ups
  // does make a difference some boards, so we do that here.
  gpio_set_pull_mode(15, GPIO_PULLUP_ONLY);   // CMD, needed in 4- and 1- line modes
  gpio_set_pull_mode(2, GPIO_PULLUP_ONLY);    // D0, needed in 4- and 1-line modes
  gpio_set_pull_mode(4, GPIO_PULLUP_ONLY);    // D1, needed in 4-line mode only
  gpio_set_pull_mode(12, GPIO_PULLUP_ONLY);   // D2, needed in 4-line mode only
  gpio_set_pull_mode(13, GPIO_PULLUP_ONLY);   // D3, needed in 4- and 1-line modes

  /*sd_card part code*/
  esp_vfs_fat_sdmmc_mount_config_t mount_config = {
    .format_if_mount_failed = true,
    .max_files = 5,
    .allocation_unit_size = 16 * 1024
  };

  esp_err_t ret = esp_vfs_fat_sdmmc_mount(MOUNT_POINT, &host, &slot_config, &mount_config, card);

  if(ret != ESP_OK){
    if (ret == ESP_FAIL) {
      ESP_LOGE(TAG, "Failed to mount filesystem.");
    } else {
      ESP_LOGE(TAG, "Failed to initialize the card (%s)", esp_err_to_name(ret));
    }
    return ESP_FAIL;
  }
  /* print card info if mount successfully */
  sdmmc_card_print_info(stdout, *card);
  return ESP_OK;
}

//static esp_err_t unmount_card(const char* base_path, sdmmc_card_t* card)
//{
//  esp_err_t err = esp_vfs_fat_sdmmc_unmount();
//  ESP_ERROR_CHECK(err);
//  return err;
//}

/* Declare the function which starts the rest server.
 * Implementation of this function is to be found in
 * rest_server.c */
esp_err_t start_rest_server(const char *base_path);
esp_err_t wifi_connect_init(const char *path);
void led_strip_task(void *args);
void ftcp_server_task(void *pvParameters);

void app_main(void)
{
  sdmmc_card_t* card = NULL;
  /*Mount the SDcard first.*/
  ESP_ERROR_CHECK(sdcard_mount(&card));

  //Initialize NVS
  esp_err_t ret = nvs_flash_init();
  if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
    ESP_ERROR_CHECK(nvs_flash_erase());
    ret = nvs_flash_init();
  }
  ESP_ERROR_CHECK(ret);

  /* initialize led strip */
  xTaskCreate(led_strip_task, "leds_task", 2048, (void * const )MOUNT_POINT, 5, NULL);

  /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
   * Read "Establishing Wi-Fi or Ethernet Connection" section in
   * examples/protocols/README.md for more information about this function.
   */
  ESP_ERROR_CHECK(wifi_connect_init(MOUNT_POINT));
  /* Start the rest server */
  ESP_ERROR_CHECK(start_rest_server(MOUNT_POINT));
  /* Start the file tcp server */
  xTaskCreate(ftcp_server_task, "ftcp_task", 8192, (void * const )MOUNT_POINT, 5, NULL);

  //deinitialize the bus after all devices are removed
//  ESP_ERROR_CHECK(unmount_card(mount_base_path, mount_card));
}
